﻿Public Class Minesweeper
    Inherits Puzzle

    Public Sub New()
        AvailableSizes = (New Integer() {8, 10, 12}).ToList
        Size = 8
    End Sub

    Public Overrides Function OnKeyPress(ByVal Key As String) As Boolean
        Select Case Key
            Case "0" To "8"
                CursorCell.g = Key
            Case "delete"
                CursorCell.g = " "
            Case Else
                Return MyBase.OnKeyPress(Key)
        End Select
    End Function

    Public Overrides Sub Load(ByVal Data As String)
        Size = Math.Sqrt(Len(Data))
        NewPuzzle()
        For k = 0 To Size * Size - 1
            Cells(k).g = Data(k)
        Next
        Invalidate()
    End Sub

    Public Overrides Function Save() As String
        Dim Text As String = ""
        For i As Integer = 1 To Size * Size
            Text &= Cells(i - 1).g
        Next
        Return Text
    End Function

    Public Overrides Sub Solve()
        ClearLog()
        For Each Cell In Cells
            Cell.f = ""
        Next
        For Each Cell In Cells
            Dim c1 As Cell = Cell
            Cell.Neighbours = New Cells(From c In Cells Where Not c Is c1 And c.g = " " And Math.Abs(c.x - c1.x) <= 1 And Math.Abs(c.y - c1.y) <= 1)
        Next
        For Each r In From c In Cells Where c.Neighbours.Count = Val(c.g) From cell In c.Neighbours Where cell.f = "" Select cell
            r.f = "*"
        Next
        Do
            Dim Found As Boolean = False
            For Each r In From c In Cells Where c.g <> " " AndAlso (From n In c.Neighbours Where n.f <> "x").Count = Val(c.g) From n In c.Neighbours Where n.f = ""
                r.n.f = "*"
                Found = True
            Next
            For Each r In From c In Cells Where c.g <> " " AndAlso (From n In c.Neighbours Where n.f = "*").Count = Val(c.g) From n In c.Neighbours Where n.f = ""
                r.n.f = "x"
                Found = True
            Next
            For Each Pair In _
                    From c1 In Cells Where c1.g <> " " From c2 In Cells Where c1.i <> c2.i AndAlso c2.g <> " " AndAlso Math.Abs(c2.x - c1.x) <= 2 AndAlso Math.Abs(c2.y - c1.y) <= 2 _
                    Let cnt1 = (From n In c1.Neighbours.Except(c2.Neighbours) Where n.f <> "x").Count Where c1.g - cnt1 = c2.g _
                    From n In c2.Neighbours.Except(c1.Neighbours) Where n.f = "" Select n
                Pair.f = "x"
                Found = True
            Next
            For Each Pair In _
                    From c1 In Cells Where c1.g <> " " From c2 In Cells Where c1.i <> c2.i AndAlso c2.g <> " " AndAlso Math.Abs(c2.x - c1.x) <= 2 AndAlso Math.Abs(c2.y - c1.y) <= 2 _
                    Let cnt1 = (From n In c1.Neighbours.Except(c2.Neighbours) Where n.f <> "x").Count Where c1.g - cnt1 = c2.g _
                    From n In c1.Neighbours.Except(c2.Neighbours) Where n.f = "" Select n
                Pair.f = "*"
                Found = True
            Next
            Invalidate()
            MsgBox(1)
            If Not Found Then Exit Do
        Loop
        CheckCell(0)
        Invalidate()
    End Sub

    Function CheckCell(ByVal i As Integer) As Boolean
        Dim a = From c In Cells Where c.g <> " " AndAlso (From n In c.Neighbours Where n.f = "*").Count > Val(c.g)
        If a.Count > 0 Then Return False
        a = From c In Cells Where c.g <> " " AndAlso (From n In c.Neighbours Where n.f <> "x").Count < Val(c.g)
        If a.Count > 0 Then Return False
        If i < 0 Then
            Invalidate()
            Application.DoEvents()
        End If
        If i = Size * Size Then Return True
        If Cells(i).f <> "" Then
            If CheckCell(i + 1) Then Return True
        Else
            For k = 1 To 2
                Cells(i).f = Choose(k, "*", "x")
                a = From c In Cells Where c.g <> " " AndAlso (From n In c.Neighbours Where n.f = "*").Count > Val(c.g)
                If a.Count = 0 Then
                    If CheckCell(i + 1) Then Return True
                End If
                Cells(i).f = ""
            Next
        End If
    End Function

    Public Overrides Sub DrawCell(ByVal e As DrawCellArgs)
        e.Invert = e.Cell.g <> " "
        If e.Cell.f = "*" Then e.Text = "♦"
        MyBase.DrawCell(e)
    End Sub

End Class